package report

import (
	"math"
	"time"

	"gddgame.cc/galaxy/utils/def"
)

//go:generate msgp
type MetricPeriod uint8

const (
	_ MetricPeriod = iota
	Second30
	Minute1
)

type MetricType uint8

const (
	allMetric MetricType = iota
	MemoryMetric
	PersistenceMetric
	BothMetric = MemoryMetric | PersistenceMetric
)

type MetricCycle byte

const (
	_ MetricCycle = iota
	Minute1Cycle
	Minute5Cycle
	Minute15Cycle
	Minute30Cycle
	Hour1Cycle
	Hour12Cycle
	Hour24Cycle
)

type MetricLogic byte

const (
	_ MetricLogic = iota
	Sum
	Avg
	Max
	Min
)

type MetricLogicHandler func([]float32) float32

func MaxHandle(values []float32) float32 {
	value := float32(0)
	for _, v := range values {
		if v > value {
			value = v
		}
	}
	return value
}

func MinHandle(values []float32) float32 {
	value := float32(math.MaxFloat32)
	for _, v := range values {
		if value == math.MaxFloat32 || v < value {
			value = v
		}
	}
	return value
}

func SumHandle(values []float32) float32 {
	value := float32(0)
	for _, v := range values {
		value += v
	}
	return value
}

func AvgHandle(values []float32) float32 {
	value := SumHandle(values)
	return value / float32(len(values))
}

type MetricFunc func(key string) float32
type MetricsFunc func() map[string]float32

//msgp:tuple Metric
type Metric struct {
	Key       string       `json:"key" msg:"key"`
	Period    MetricPeriod `json:"period" msg:"period"`
	Type      MetricType   `json:"type" msg:"type"`
	NodeLogic MetricLogic  `json:"node" msg:"node"`
	TimeLogic MetricLogic  `json:"time" msg:"time"`

	exec     MetricFunc
	duration time.Duration
	lastTime *time.Time
	mock     bool
}

func (metric *Metric) Marshal() ([]byte, error) {
	return metric.MarshalMsg(nil)
}

func (metric *Metric) Unmarshal(b []byte) error {
	_, err := metric.UnmarshalMsg(b)
	return err
}
func (metric *Metric) Copy(o def.OptimizeSerializer) {
	if b, ok := o.(*Metric); ok {
		metric.Key = b.Key
		metric.Period = b.Period
		metric.Type = b.Type
		metric.NodeLogic = b.NodeLogic
		metric.TimeLogic = b.TimeLogic
	}
}
func (metric *Metric) Release() {

}
func (metric *Metric) Alloc() {

}
func (metric *Metric) Init(exec MetricFunc) {
	metric.exec = exec
	var d time.Duration
	switch metric.Period {
	case Minute1:
		d = time.Minute
	case Second30:
		d = time.Second * 30
	}
	metric.duration = d
}
